package com.zyg.seckill.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zyg.common.utils.MyDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zyg.seckill.dao.TbSeckillGoodsMapper;
import com.zyg.seckill.entity.TbSeckillGoods;
import com.zyg.seckill.service.TbSeckillGoodsService;
/**
 * Created by WF on 2021/11/25 14:57
 */
@Service
@EnableScheduling
public class TbSeckillGoodsServiceImpl extends ServiceImpl<TbSeckillGoodsMapper, TbSeckillGoods> implements TbSeckillGoodsService{

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private TbSeckillGoodsMapper goodsMapper;
    //1. 得到秒杀商品列表
    @Scheduled(cron = "0/30 * * * * ?")
    public void loadDataFromRedis() {
        //1.1 得到日期范围集合
        List<Date> dateMenus = MyDate.getDateMenus();
        // for (Date dateMenu : dateMenus) {
        //     System.out.println("--------------------->" + MyDate.getDateStr(dateMenu));
        // }
        //1.2 遍历这个集合
        //1.2.1 构造查询条件
        for (Date dt : dateMenus) {
            QueryWrapper<TbSeckillGoods> wrapper = new QueryWrapper<>();
            //第一件事：判断是否在某个秒杀时间之内
            //1.2.2 开始时间大于时间段的某个时间
            wrapper.ge("start_time",dt);
            //1.2.3 结束时间小于某个时间加2小时
            wrapper.lt("end_time",MyDate.addDateHour(dt,2));

            //第二件事：判断数据本身的数据
            //1.2.4 状态值为1,代表审核通过
            wrapper.eq("status",1);
            //1.2.5 库存量大于0
            wrapper.gt("stock_count",0);

            //第三件事：排除数据库中己经存放到索引库中的商品
            //1.2.6 得到redis中的秒杀商品的key的集合

            String dateStr = MyDate.getDateStr(dt);
            System.out.println("dateStr =========> " + dateStr);

            Set<Object> keys = redisTemplate.boundHashOps("seckillGoods_" + MyDate.getDateStr(dt)).keys();
            if(keys != null && keys.size() > 0) {
                wrapper.notIn("id", keys);
            }

            //1.3 根据条件查询出商品

            List<TbSeckillGoods> seckillGoods = goodsMapper.selectList(wrapper);
            System.out.println("seckillGoods = " + seckillGoods);
            //1.4 将商品放到redis中
            BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps("seckillGoods_" + MyDate.getDateStr(dt));
            for (TbSeckillGoods seckillGood : seckillGoods) {
                //1.4.1 添加数据
                operations.put(seckillGood.getId()+"", JSON.toJSONString(seckillGood));
                //1.4.2 设置到期时间
                //operations.expire(MyDate.addDateHour(dt,2).getHours() - new Date().getHours(), TimeUnit.HOURS);
                //1.5 以SeckillGoodsCountList_商品id为key，以数组（数组个数为商品数量，数组元素内容为id）放到redis中
                //商品个数
                Integer len = seckillGood.getStockCount();
                String[] ids = new String[len];
                for (int i = 0; i < ids.length; i++) {
                    ids[i] = seckillGood.getId() + "";
                }
                redisTemplate.boundListOps("SeckillGoodsCountList_" + seckillGood.getId()).leftPushAll(ids);
                //1.6 以SeckillGoodsCount为大key，以商品id为小key，作一个对应商品的自增键，以后下单扣完库存的实际数量，就是这里的自增键
                redisTemplate.boundHashOps("SeckillGoodsCount").put(seckillGood.getId()+"",seckillGood.getStockCount());

            }

        }
        System.out.println("正在读取数据。。。");

    }
    //2. 根据时间段加载数据
    @Override
    public List<TbSeckillGoods> findSecillGoods(String time) {
        //2.1 根据大key得到BoundHashOperations
        BoundHashOperations<String, String, String> boundHashOperations = redisTemplate.boundHashOps("seckillGoods_" + time);
        //2.2 得到hash的值的集合
        List<String> values = boundHashOperations.values();
        System.out.println("values = " + values);

        //2.3 处理集合并返回
        List<TbSeckillGoods> collect = values.stream().map(m -> JSON.parseObject(m, TbSeckillGoods.class)).collect(Collectors.toList());
        return collect;
    }
}
